﻿# -*- coding:utf-8 -*-
import enum

# 测试开关，打开时会打印每一次指令执行后内存的当前状态
Debug = False

# 内存模拟部分
PoolSize = 256 * 1024
PoolSize = 1000
memory = [] # 模拟内存
text = 0 # 代码段的起始位置
data = 0 # 数据段的起始位置
heap = 0 # 堆的起始位置
stack = 0 # 栈的栈顶位置
bp = 0 # 基址
sp = 0 # 
pc = 0 # 程序计数器
ax = 0 # 寄存器（本虚拟机只有一个寄存器）

# 定义虚拟机指出的指令集系统，完全按照c4的指令集系统实现
Inst = enum.Enum("Inst", 
(
    "LEA", "IMM", "JMP", "CALL", "JZ", "JNZ", "ENT", "ADJ", "LEV", "LI", "LC", "SI", "SC", "PUSH",
    "OR", "XOR", "AND", "EQ", "NE", "LT", "GT", "LE", "GE", "SHL", "SHR", "ADD", "SUB", "MUL", "DIV", "MOD",
    "OPEN", "READ", "CLOS", "PRTF", "MALC", "FREE", "MSET", "MCMP", "EXIT",
))

# 词法分析
def next():
    pass

# 语法分析
def program():
    pass

# 表达式解析
def expression():
    pass

# 虚拟机入口
def eval():
    i = 0
    global memory, data, heap, bp, sp, pc, ax
    while True:
        op = memory[pc]
        pc += 1
        if Debug:
            print("##### {} #####".format(i + 1))
            print("op = {}, pc = {}, ax = {}".format(op, pc - 1, ax))
        if op == Inst.LEA:
            # 通过bp快速检索到变量的位置
            ax = bp + memory[pc]
            pc += 1
        elif op == Inst.IMM:
            ax = memory[pc]
            pc += 1
        elif op == Inst.JMP:
            pc = memory[pc]
        elif op == Inst.CALL:
            # 记录下来调用返回时执行的下一条指令
            sp -= 1
            memory[sp] = pc + 1
            # 方法跳转
            pc = memory[pc]
        elif op == Inst.JZ:
            pc = memory[pc] if ax == 0 else pc + 1
        elif op == Inst.JNZ:
            pc = memory[pc] if ax != 0 else pc + 1
        elif op == Inst.ENT:
            # 记录下来旧的bp
            sp -= 1
            memory[sp] = bp
            # 开辟出局部变量的空间
            bp = sp
            sp = sp - memory[pc]
            pc += 1
        elif op == Inst.ADJ:
            sp = sp + memory[pc]
            pc += 1
        elif op == Inst.LEV:
            sp = bp
            bp = memory[sp]
            sp += 1
            pc = memory[sp]
            sp += 1
        elif op == Inst.LI or op == Inst.LC:
            ax = memory[ax]
        elif op == Inst.SI or op == Inst.SC:
            memory[memory[sp]] = ax
            sp += 1
        elif op == Inst.PUSH:
            sp -= 1
            memory[sp] = ax
        elif op == Inst.OR:
            ax = memory[sp] | ax
            sp += 1
        elif op == Inst.XOR:
            ax = memory[sp] ^ ax
            sp += 1
        elif op == Inst.AND:
            ax = memory[sp] & ax
            sp += 1
        elif op == Inst.EQ:
            ax = memory[sp] == ax
            sp += 1
        elif op == Inst.NE:
            ax = memory[sp] != ax
            sp += 1
        elif op == Inst.LT:
            ax = 1 if memory[sp] < ax else 0
            sp += 1
        elif op == Inst.GT:
            ax = 1 if memory[sp] > ax else 0
            sp += 1
        elif op == Inst.LE:
            ax = 1 if memory[sp] <= ax else 0
            sp += 1
        elif op == Inst.GE:
            ax = 1 if memory[sp] >= ax else 0
            sp += 1
        elif op == Inst.SHL:
            ax = memory[sp] << ax
            sp += 1
        elif op == Inst.SHR:
            ax = memory[sp] >> ax
            sp += 1
        elif op == Inst.ADD:
            ax = memory[sp] + ax
            sp += 1
        elif op == Inst.SUB:
            ax = memory[sp] - ax
            sp += 1
        elif op == Inst.MUL:
            ax = memory[sp] * ax
            sp += 1
        elif op == Inst.DIV:
            ax = memory[sp] / ax
            sp += 1
        elif op == Inst.MOD:
            ax = memory[sp] % ax
            sp += 1
        elif op == Inst.PRTF:
            # 注意：这里这么书写的原因是当执行PRTF的时候，当前帧的状态应该是
            #               pc
            # text = [PRTF, ADJ , 2]
            #          sp
            # stack = [100, "i = %d", "Other"]
            # 可以看到memory[pc + 1]取到的是参数数量2
            # temp指向栈中print方法的第一个参数的上一个位置
            temp = sp + memory[pc + 1]
            l = []
            for i in range(memory[pc + 1] - 1):
                l.append(memory[temp -2 - i])
            s = memory[temp - 1] % tuple(l)
            ax = len(s)
            print(s)
        elif op == Inst.EXIT:
            print("exit {}".format(memory[sp]))
            return memory[sp]
        else:
            # 不能识别的操作符
            print("unknown inst op = {}".format(op))
            return
        
        if Debug:
            print("data = {}".format(memory[data:data + 5]))
            print("stack = {}".format(memory[sp:]))
            print("heap = {}".format(memory[heap:heap + 25]))
            print("op = {}, pc = {}, ax = {}".format(op, pc, ax))
        i += 1

i_code = 0
def _code_reset():
    global i_code
    i_code = text
    for i in range(PoolSize):
        memory[text + i] = "#"
        
def _code_append(op, v = None):
    global i_code
    memory[i_code] = op
    i_code += 1
    if v == None:
        return
    memory[i_code] = v
    i_code += 1
    
i_data = 0
def _data_reset():
    global i_data
    i_data = data
    for i in range(PoolSize):
        memory[data + i] = "#"
def _data_append(d):
    global i_data
    memory[i_data] = d
    i_data += 1

def main():
    global memory, text, data, heap, stack, bp, sp, pc, ax
    # 为了方便进行调试打印，对于未被使用的内存，使用"#"进行标记站位
    memory = ["#"] * 4 * PoolSize
    text = 0
    data = PoolSize
    heap = 2 * PoolSize
    stack = 4 * PoolSize
    bp = sp = 4 * PoolSize
    pc = ax = 0
    
    # # 实现简单的 1 + 2的功能
    # _code_reset()
    # _code_append(Inst.IMM, 1)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.IMM, 2)
    # _code_append(Inst.ADD)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.EXIT)
    
    # # 实现简单的打印输出功能
    # # printf("i = %d, j = %d" % (100, 200))
    # _code_reset()
    # _code_append(Inst.IMM, "i = %d, j = %d")
    # _code_append(Inst.PUSH)
    # _code_append(Inst.IMM, 100)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.IMM, 200)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.PRTF)
    # _code_append(Inst.ADJ, 3)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.EXIT)
    
    # # # 实现简单的if语句
    # # if(10 > 2){
    # #     printf("10 is max")
    # # }else{
    # #     printf("2 is max")
    # # }
    # _code_reset()
    # _code_append(Inst.IMM, 10)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.IMM, 2)
    # _code_append(Inst.GT)
    # _code_append(Inst.JZ, 13)
    # _code_append(Inst.IMM, "10 is max")
    # _code_append(Inst.PUSH)
    # _code_append(Inst.JMP, 16)
    # _code_append(Inst.IMM, "2 is max")
    # _code_append(Inst.PUSH)
    # _code_append(Inst.PRTF)
    # _code_append(Inst.ADJ, 1)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.EXIT)
    
    # # 实现简单的函数调用
    # # int add(int a, int b) {
    # #     int ret;
    # #     ret = a + b;
    # #     return ret;
    # # }
    # # int main () {
    # #     printf("1 + 2 = %d", add(1, 2));
    # #     return 0;
    # # }
    # _code_reset()
    # _code_append(Inst.IMM, "1 + 2 = %d")
    # _code_append(Inst.PUSH)
    # _code_append(Inst.IMM, 1)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.IMM, 2)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.CALL, 19)
    # _code_append(Inst.ADJ, 2)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.PRTF)
    # _code_append(Inst.ADJ, 2)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.EXIT)
    # _code_append(Inst.ENT, 1)
    # _code_append(Inst.LEA, -1)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.LEA, 3)
    # _code_append(Inst.LI)
    # _code_append(Inst.PUSH)
    # _code_append(Inst.LEA, 2)
    # _code_append(Inst.LI)
    # _code_append(Inst.ADD)
    # _code_append(Inst.SI)
    # _code_append(Inst.LEV)

    eval()
main()
    